﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArchMethodLibrary.Utils;
using WallCreateAndEdit.WallModule.SearchExternalLoop;

namespace WallCreateAndEdit.WallModule
{
	public class WallCreatorByCurve
	{
		public WallCreatorByCurve(UIApplication uiApp, Document doc)
		{
			this.m_uiApp = uiApp;
			this.m_doc = doc;
		}

		public void Sort(List<Level> levelList)
		{
			bool flag = false;
			int num = 1;
			while (num < levelList.Count && !flag)
			{
				flag = true;
				for (int i = 0; i < levelList.Count - num; i++)
				{
					try
					{
						if (levelList[i].Elevation > levelList[i + 1].Elevation)
						{
							flag = false;
							Level value = levelList[i];
							levelList[i] = levelList[i + 1];
							levelList[i + 1] = value;
						}
					}
					catch
					{
					}
				}
				num++;
			}
		}

		public List<List<Wall>> CreateWallByCurve(List<Curve> curveList, WallType wallType, ElementId levelId, double offset, double wallHeight, bool isBreak)
		{
			List<List<Wall>> list = new List<List<Wall>>();
			Level currentViewLevel = AssistFunc.GetCurrentViewLevel(this.m_doc);
			if (currentViewLevel == null)
			{
				return list;
			}
			if (isBreak)
			{
				double num = 0.0;
				if (levelId == ElementId.InvalidElementId)
				{
					num = currentViewLevel.Elevation + wallHeight;
				}
				else
				{
					Level level = this.m_doc.GetElement(levelId) as Level;
					num = level.Elevation;
				}
				List<Level> sortLevels = Common.GetSortLevels(this.m_doc, currentViewLevel.Elevation, num);
				List<ElementId> list2 = new List<ElementId>();
				foreach (Level level2 in sortLevels)
				{
					if (levelId == ElementId.InvalidElementId && Geometry.IsEqual(num, level2.Elevation))
					{
						list2.Add(ElementId.InvalidElementId);
						break;
					}
					list2.Add(level2.Id);
				}
				using (List<Curve>.Enumerator enumerator2 = curveList.GetEnumerator())
				{
					while (enumerator2.MoveNext())
					{
						Curve curve = enumerator2.Current;
						List<Wall> list3 = new List<Wall>();
						for (int i = 0; i < list2.Count; i++)
						{
							ElementId elementId = list2[i];
							Level level3 = this.m_doc.GetElement(elementId) as Level;
							ElementId elementId2 = ElementId.InvalidElementId;
							if (i < list2.Count - 1)
							{
								elementId2 = list2[i + 1];
							}
							if (level3 == null || Geometry.IsEqual(num, level3.Elevation))
							{
								break;
							}
							Wall wall = null;
							if (curve.GetType() == typeof(Line))
							{
								Line line = curve as Line;
								if (this.CreateLinearWall(line, wallType, offset, level3, ref wall))
								{
									list3.Add(wall);
								}
							}
							else
							{
								if (!(curve.GetType() == typeof(Arc)))
								{
									break;
								}
								Arc arc = curve as Arc;
								if (this.CreateArcWall(arc, wallType, offset, level3, ref wall))
								{
									list3.Add(wall);
								}
							}
							if (wall != null)
							{
								wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(elementId2);
								if (elementId2 == ElementId.InvalidElementId)
								{
									wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).Set(num - level3.Elevation);
								}
							}
						}
						list.Add(list3);
					}
					return list;
				}
			}
			foreach (Curve curve2 in curveList)
			{
				List<Wall> list4 = new List<Wall>();
				Wall wall2 = null;
				if (curve2.GetType() == typeof(Line))
				{
					Line line2 = curve2 as Line;
					if (this.CreateLinearWall(line2, wallType, offset, currentViewLevel, ref wall2))
					{
						list4.Add(wall2);
					}
				}
				else
				{
					if (!(curve2.GetType() == typeof(Arc)))
					{
						continue;
					}
					Arc arc2 = curve2 as Arc;
					if (this.CreateArcWall(arc2, wallType, offset, currentViewLevel, ref wall2))
					{
						list4.Add(wall2);
					}
				}
				if (wall2 != null)
				{
					list.Add(list4);
					wall2.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(levelId);
					if (levelId == ElementId.InvalidElementId)
					{
						wall2.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).Set(wallHeight);
					}
				}
			}
			return list;
		}

		public void JoinLinkWalls(List<List<Wall>> wallList)
		{
			Transaction transaction = new Transaction(this.m_doc);
			transaction.Start("JoinWalls");
			foreach (List<Wall> list in wallList)
			{
				for (int i = 1; i < list.Count; i++)
				{
					this.WallJoinWall(list[i - 1], list[i]);
				}
			}
			transaction.Commit();
		}

		private void WallJoinWall(Wall wallBottom, Wall wallTop)
		{
			try
			{
				JoinGeometryUtils.JoinGeometry(this.m_doc, wallBottom, wallTop);
			}
			catch (Exception ex)
			{
				string message = ex.Message;
			}
		}

		private bool CreateLinearWall(Line line, WallType WallType, double offset, Level levelStart, ref Wall newWall)
		{
			double num = Common.MMToFeet(4000.0);
			if (Geometry.IsEqual(offset, 0.0))
			{
				newWall = Wall.Create(this.m_doc, line, WallType.Id, levelStart.Id, num, 0.0, false, false);
			}
			else
			{
				XYZ xyz = line.GetEndPoint(0);
				XYZ xyz2 = line.GetEndPoint(1);
				XYZ xyz3 = (xyz2 - xyz).Normalize();
				xyz3 = Geometry.RotateTo(xyz3, Math.PI*.5, XYZ.BasisZ);
				xyz3 *= offset;
				xyz += xyz3;
				xyz2 += xyz3;
				Line line2 = YJKLineEx.YJKGetBound(xyz, xyz2);
				newWall = Wall.Create(this.m_doc, line2, WallType.Id, levelStart.Id, num, 0.0, false, false);
			}
			if (this.OverLapWithOtherWall(newWall))
			{
				this.m_doc.DeleteElement(newWall);
				newWall = null;
				return false;
			}
			return true;
		}

		private bool CreateArcWall(Arc arc, WallType WallType, double offset, Level levelStart, ref Wall newWall)
		{
			double num = Common.MMToFeet(4000.0);
			if (Geometry.IsEqual(offset, 0.0))
			{
				newWall = Wall.Create(this.m_doc, arc, WallType.Id, levelStart.Id, num, 0.0, false, false);
			}
			else
			{
				XYZ center = arc.Center;
				XYZ xyz = arc.GetEndPoint(0);
				XYZ xyz2 = arc.GetEndPoint(1);
				XYZ xyz3 = (center - xyz).Normalize() * offset;
				XYZ xyz4 = (center - xyz2).Normalize() * offset;
				if (arc.Normal.IsAlmostEqualTo(XYZ.BasisZ))
				{
					xyz += xyz3;
					xyz2 += xyz4;
				}
				else
				{
					xyz -= xyz3;
					xyz2 -= xyz4;
				}
				XYZ radianPnt = Geometry.CalculatMidPoint(xyz, xyz2, center, arc.Normal);
				Arc arc2 = this.m_uiApp.Application.CreatYJKArc(xyz, xyz2, radianPnt);
				newWall = Wall.Create(this.m_doc, arc2, WallType.Id, levelStart.Id, num, 0.0, false, false);
			}
			return true;
		}

		private bool OverLapWithOtherWall(Wall curWall)
		{
			bool result;
			try
			{
				FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_doc);
				ElementIntersectsElementFilter elementIntersectsElementFilter = new ElementIntersectsElementFilter(curWall);
				IList<Element> list = filteredElementCollector.OfClass(typeof(Wall)).WherePasses(elementIntersectsElementFilter).ToElements();
				Curve wallCurve = WallAssistFunc.GetWallCurve(curWall);
				foreach (Element element in list)
				{
					Wall wall = element as Wall;
					if (!(wall.Id == curWall.Id) && wall != null)
					{
						Curve wallCurve2 = WallAssistFunc.GetWallCurve(wall);
						if (CurveAssistFunc.GetOverlapType(this.m_uiApp, wallCurve, wallCurve2) != OverlapType.eNotOverlap)
						{
							return true;
						}
					}
				}
				result = false;
			}
			catch
			{
				result = false;
			}
			return result;
		}

		public static List<Curve> FormatCurve(Curve curve, List<Curve> curves, Document doc, bool includeEnds)
		{
			List<Curve> list = new List<Curve>();
			IntersectionResultArray intersectionResultArray = null;
			List<XYZ> list2 = new List<XYZ>();
			foreach (Curve curve2 in curves)
			{
				if (!curve.Equals(curve2))
				{
                    curve.Intersect(curve2, out intersectionResultArray);
					if (intersectionResultArray != null)
					{
						for (int i = 0; i < intersectionResultArray.Size; i++)
						{
                            list2.Add(intersectionResultArray.get_Item(i).XYZPoint);
						}
					}
				}
			}
			if (includeEnds)
			{
				list2.Add(curve.GetEndPoint(0));
				list2.Add(curve.GetEndPoint(1));
			}
			AssistFunc.CompressArray(list2);
			if (list2.Count <= 1)
			{
				return list;
			}
			Line line = curve as Line;
			if (line != null)
			{
				list2.Sort(new DistanceComparer(line.GetEndPoint(0)));
				for (int j = 0; j < list2.Count - 1; j++)
				{
					XYZ xyz = list2.ElementAt(j);
					XYZ xyz2 = list2.ElementAt(j + 1);
					if (!xyz.IsAlmostEqualTo(xyz2))
					{
						Line item = YJKLineEx.YJKGetBound(xyz, xyz2);
						list.Add(item);
					}
				}
			}
			Arc arc = curve as Arc;
			if (arc != null)
			{
				XYZ center = arc.Center;
				XYZ hyendPoint = arc.GetEndPoint(1);
				if (arc.Normal.IsAlmostEqualTo(XYZ.BasisZ))
				{
					hyendPoint = arc.GetEndPoint(0);
				}
				list2.Sort(new RotationComparer(hyendPoint, center));
				for (int k = 0; k < list2.Count - 1; k++)
				{
					XYZ xyz = list2.ElementAt(k);
					XYZ xyz2 = list2.ElementAt(k + 1);
					if (!xyz.IsAlmostEqualTo(xyz2))
					{
						XYZ radianPnt = Geometry.CalculatMidPoint(xyz, xyz2, center, XYZ.BasisZ);
						Arc item2 = doc.Application.CreatYJKArc(xyz, xyz2, radianPnt);
						list.Add(item2);
					}
				}
			}
			return list;
		}

		private UIApplication m_uiApp;

		private Document m_doc;
	}
}
